home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-serious-
/
misc
/
db3.6-beta
/
db3.6-beta-src
/
select.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-11-30
|
25KB
|
793 lines
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <libraries/commodities.h> /* This has a nice qualifier #define */
#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/dos.h> /* Delay() for debugging */
#include <string.h>
#include <stdlib.h> /* malloc & free */
#include <stdio.h> /* debugging */
#include "db.h"
#include "Select_P.h"
#include "dbparser.h"
#include "dbGUI.h" /* We use db's font instead of the screen font */
#define MARGIN 4
#define TOGGLE_LED *(UBYTE *)0xbfe001 ^= 2
extern struct Pro *CurrentPro;
/* We use db's font engine instead.
static struct TextAttr *Font, Attr;
static UWORD FontX, FontY;
*/
/*
void FlashLed(void)
{
int i;
for (i=0; i<20; i++) {
TOGGLE_LED;
Delay(10);
}
}
*/
/**********************************************************************/
/* Support functions */
/**********************************************************************/
static UWORD ComputeX( UWORD value )
{
return(( UWORD )((( FontX * value ) + 4 ) / 8 ));
}
static UWORD ComputeY( UWORD value )
{
return(( UWORD )((( FontY * value ) + 6 ) / 13 ));
}
/*
static void ComputeFont( UWORD width, UWORD height )
{
static UWORD OffX, OffY;
Font = &Attr;
Font->ta_Name = (STRPTR)Scr->RastPort.Font->tf_Message.mn_Node.ln_Name;
Font->ta_YSize = FontY = Scr->RastPort.Font->tf_YSize;
FontX = Scr->RastPort.Font->tf_XSize;
OffX = Scr->WBorLeft;
OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;
if ( width && height ) {
if (( ComputeX( width ) + OffX + Scr->WBorRight ) > Scr->Width )
goto UseTopaz;
if (( ComputeY( height ) + OffY + Scr->WBorBottom ) > Scr->Height )
goto UseTopaz;
}
return;
UseTopaz:
Font->ta_Name = (STRPTR)"topaz.font";
FontX = FontY = Font->ta_YSize = 8;
}
*/
static void MyCreateAllGadgets(Select *s)
{
struct Gadget *g;
static struct NewGadget ng[] =
{
4, 4, 213, 229, NULL , NULL, GD_SELLview, 0, NULL, (APTR)SELLviewClicked,
4, 232, 213, 229, (char *)"+", NULL, GD_SELLadd , 0, NULL, (APTR)SELLaddClicked,
4, 4, 213, 229, (char *)"-", NULL, GD_SELLdel , 0, NULL, (APTR)SELLdelClicked
};
g = CreateContext( &s->SelGList );
// listview
ng[0].ng_VisualInfo = VisualInfo;
ng[0].ng_TextAttr = Font;
ng[0].ng_LeftEdge = s->SelWnd->BorderLeft + MARGIN;
ng[0].ng_TopEdge = s->SelWnd->BorderTop + MARGIN;
ng[0].ng_Width = s->SelWnd->Width - s->SelWnd->BorderLeft - s->SelWnd->BorderRight - 2*MARGIN;
ng[0].ng_Height = (s->SelWnd->Height - s->SelWnd->BorderTop - s->SelWnd->BorderBottom - 2*MARGIN) - (2*MARGIN + FontY);
// button +
ng[1].ng_VisualInfo = VisualInfo;
ng[1].ng_TextAttr = Font;
ng[1].ng_LeftEdge = s->SelWnd->BorderLeft + MARGIN;
ng[1].ng_TopEdge = s->SelWnd->BorderTop + ng[0].ng_Height + 2*MARGIN;
ng[1].ng_Width = (s->SelWnd->Width/2) - 2*MARGIN;
ng[1].ng_Height = FontY +4;
// button -
ng[2].ng_VisualInfo = VisualInfo;
ng[2].ng_TextAttr = Font;
ng[2].ng_LeftEdge = s->SelWnd->BorderLeft + ng[1].ng_Width + MARGIN + 1;
ng[2].ng_TopEdge = ng[1].ng_TopEdge;
ng[2].ng_Width = ng[1].ng_Width;
ng[2].ng_Height = ng[1].ng_Height;
s->ListView = g = CreateGadget(LISTVIEW_KIND, g, &ng[0],
GTLV_Labels, &s->SelList,
GTLV_ShowSelected, NULL,
GTLV_Selected, s->SelIndex,
GTLV_MakeVisible, s->SelIndex,
TAG_DONE);
g = CreateGadget(BUTTON_KIND, g, &ng[1],
GT_Underscore, '_',
TAG_DONE);
g = CreateGadget(BUTTON_KIND, g, &ng[2],
GT_Underscore, '_',
TAG_DONE);
AddGList(s->SelWnd, s->SelGList, -1, -1, NULL);
RefreshWindowFrame(s->SelWnd);
RefreshGList(s->SelGList, s->SelWnd, NULL, -1);
GT_RefreshWindow( s->SelWnd, NULL ); /* Must also be called */
}
static void UpdateListView(Select *s)
{
if (GadToolsBase->lib_Version < 39) {
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL,
GTLV_Selected, s->SelIndex,
GTLV_Top, s->SelIndex,
TAG_END);
}
else {
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL,
GTLV_Selected, s->SelIndex,
GTLV_MakeVisible, s->SelIndex,
TAG_END);
}
}
static struct Node *FindIndex(struct List *list, int idx)
{
/* Returns the node with index idx in the list, (first node is 0) */
struct Node *cn; /* Current Node */
for (cn = list->lh_Head; idx; cn = cn->ln_Succ, idx--);
return cn;
}
static int IndexInList(struct List *list, char *str)
{
/* returs -1 if str doesn't match somewhere in list */
int len = strlen(str);
struct Node *node;
int i;
for (node = list->lh_Head, i=0;
node->ln_Succ && Strnicmp(str, node->ln_Name, len);
node = node->ln_Succ, i++);
if (node->ln_Succ) return i;
return -1;
}
static int NextMatch(struct Node *cnode, char *str)
{
/* returs -1 if str doesn't match somewhere in list */
int len = strlen(str);
struct Node *node;
int i;
if (!cnode->ln_Succ) return -1;
for (node = cnode->ln_Succ, i=1;
node->ln_Succ && Strnicmp(str, node->ln_Name, len);
node = node->ln_Succ, i++);
if (node->ln_Succ) return i;
return -1;
}
static int PrevMatch(struct Node *cnode, char *str)
{
/* returs -1 if str doesn't match somewhere in list */
int len = strlen(str);
struct Node *node;
int i;
if (!cnode->ln_Pred) return -1;
for (node = cnode->ln_Pred, i=1;
node->ln_Pred && Strnicmp(str, node->ln_Name, len);
node = node->ln_Pred, i++);
if (node->ln_Pred) return i;
return -1;
}
/**********************************************************************/
/* Event handlers */
/**********************************************************************/
static int SelNewSize(Select *s)
{
/* routine for "IDCMP_NEWSIZE". */
RemoveGList(s->SelWnd, s->SelGList, -1);
FreeGadgets(s->SelGList);
EraseRect(s->SelWnd->RPort, s->SelWnd->BorderLeft, s->SelWnd->BorderTop,
s->SelWnd->Width - s->SelWnd->BorderRight, s->SelWnd->Height - s->SelWnd->BorderBottom);
MyCreateAllGadgets(s);
return SEL_PRIVATE;
}
static int SELOkClicked(Select *s)
{
/* routine when gadget "_Ok" is clicked. */
/* CloseSelect(s); */
return SEL_OK;
}
static int SELLaddClicked(Select *s)
{
struct FldInfo *f, *last = NULL;
// lets create the new one...
if(!(f = NewFldInfo()))
{
DisplayBeep(0);
return MEM_ERR;
}
strcpy(f->Name, "New");
// let's find the last one
// and attach the new to the list
if(CurrentPro->FirstFldInfo)
{
char tmp[5];
int Count=1;
for(last = CurrentPro->FirstFldInfo; last->Next; last = last->Next,Count++);
sprintf(tmp, "_%ld", Count);
strcat(f->Name, tmp);
last->Next = f;
}
else
CurrentPro->FirstFldInfo = f;
AddStringLast(s, f->Name);
return(SEL_PRIVATE);
}
static int SELLdelClicked(Select *s)
{
DoASCIIParsing();
return(SEL_PRIVATE);
}
static int SELLviewClicked(Select *s)
{
/* routine when listview gadget is clicked. */
/* Handle doubleclicks.. */
if (DoubleClick(s->StartSecs, s->StartMicros, s->SelMsg.Seconds, s->SelMsg.Micros)
&& s->SelMsg.Code == s->SelIndex) {
s->StartSecs = s->StartMicros = 0; /* Prevent "triple clicks" */
s->SelIndex = s->SelMsg.Code;
return SELOkClicked(s);
}
else {
s->StartSecs = s->SelMsg.Seconds;
s->StartMicros = s->SelMsg.Micros;
s->SelIndex = s->SelMsg.Code;
}
return SEL_SELECT;
}
static int SelCloseWindow(Select *s)
{
/* routine for "IDCMP_CLOSEWINDOW". */
CloseSelect(s);
return SEL_CANCEL;
}
static int SELCancelClicked(Select *s)
{
/* routine when gadget "_Cancel" is clicked. */
return SelCloseWindow(s);
}
static int SelVanillaKey(Select *s)
{
/* routine for "IDCMP_VANILLAKEY". */
int len;
int index;
struct List *list = (struct List *) &s->SelList;
switch (s->SelMsg.Code) {
case '\r' :
return SELOkClicked(s);
break;
case VANILLA_ESC :
return SELCancelClicked(s);
break;
case VANILLA_DEL :
s->SelCompleteBuf[1] = '\0';
case '\b' :
if (len = strlen(s->SelCompleteBuf)) {
s->SelCompleteBuf[len-1] = '\0';
if ((index = IndexInList(list, s->SelCompleteBuf)) >= 0) {
s->SelIndex = index;
UpdateListView(s);
}
}
SetWindowTitles(s->SelWnd, s->SelWdt ,(UBYTE *)-1);
break;
case '\t' :
if ((index = NextMatch(FindIndex(list, s->SelIndex), s->SelCompleteBuf)) >= 0) {
s->SelIndex += index;
UpdateListView(s);
} else DisplayBeep(Scr);
break;
default :
if ((len = strlen(s->SelCompleteBuf)) < COMPLETEBUFSIZ-1 ) {
s->SelCompleteBuf[len] = s->SelMsg.Code;
s->SelCompleteBuf[len+1] = '\0';
if ((index = IndexInList(list, s->SelCompleteBuf)) >= 0) {
s->SelIndex = index;
UpdateListView(s);
SetWindowTitles(s->SelWnd, s->SelWdt ,(UBYTE *)-1);
}
else {
s->SelCompleteBuf[len] = '\0';
DisplayBeep(Scr);
}
}
break;
}
return SEL_SELECT;
}
static int SelRawKey(Select *s)
{
/* routine for "IDCMP_RAWKEY". */
int index;
struct List *list = (struct List *)&s->SelList;
int rows = (s->ListView->Height-4)/FontY; /* Rows visible in listview. Ugly but works */
switch (s->SelMsg.Code) {
case RAW_UP :
if (s->SelIndex == 0) return SEL_PRIVATE;
if (s->SelMsg.Qualifier & IXSYM_ALTMASK)
s->SelIndex = 0;
else if (s->SelMsg.Qualifier & IXSYM_SHIFTMASK) {
s->SelIndex -= rows-1;
if (s->SelIndex < 0) s->SelIndex = 0;
}
else s->SelIndex--;
break;
case RAW_DOWN :
if (s->SelIndex >= s->SelTotal-1) return SEL_PRIVATE;
if (s->SelMsg.Qualifier & IXSYM_ALTMASK)
s->SelIndex = s->SelTotal - 1;
else if (s->SelMsg.Qualifier & IXSYM_SHIFTMASK) {
s->SelIndex += rows-1;
if (s->SelIndex > s->SelTotal-1) s->SelIndex = s->SelTotal - 1;
}
else s->SelIndex++;
break;
case RAW_TAB :
if ((index = PrevMatch(FindIndex(list, s->SelIndex), s->SelCompleteBuf)) >= 0) {
s->SelIndex -= index;
UpdateListView(s);
} else DisplayBeep(Scr);
break;
case RAW_HELP :
return SEL_HELP;
break;
default :
return SEL_PRIVATE;
}
UpdateListView(s);
return SEL_SELECT;
}
/**********************************************************************/
/* Interface functions */
/**********************************************************************/
BOOL FixSelectSize(Select *s, int n)
{
/* Makes the Select object allocate memory for n elements in one chunk for */
/* all fields. It is illegal to add more fields than allocated after this */
/* Use RemoveAllFields() to free up everything. */
if (!(s->NodeArray = malloc(n * sizeof(struct Node)))) return FALSE;
s->FirstFree = 0;
return TRUE;
}
char *SelectedString(Select *s)
{
/* Returns the selected string */
return FindIndex((struct List *)&s->SelList, s->SelIndex)->ln_Name;
}
void UpdateString(Select *s, int index, char *newstring)
{
/* Changes a string. */
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
FindIndex((struct List *)&s->SelList, index)->ln_Name = newstring;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
}
/* // I comment this to save space
char *AddStringFirst(Select *s, char *str)
{
struct Node *newnode;
if (s->NodeArray) newnode = s->NodeArray[s->FirstFree++];
else if (!(newnode = (struct Node *)malloc(sizeof(struct Node)))) return str;
newnode->ln_Name = str;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
AddHead((struct List *)&s->SelList, newnode);
s->SelTotal++;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
return str;
}
*/
char *AddStringLast(Select *s, char *str)
{
struct Node *newnode;
if (s->NodeArray) newnode = &s->NodeArray[s->FirstFree++];
else if (!(newnode = (struct Node *)malloc(sizeof(struct Node)))) return str;
newnode->ln_Name = str;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
AddTail((struct List *)&s->SelList, newnode);
s->SelTotal++;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
return str;
}
/* // I comment this to save space
char *AddString(Select *s, char *str, int index)
{
struct Node *newnode;
if (s->NodeArray) newnode = &s->NodeArray[s->FirstFree++];
else if (!(newnode = (struct Node *)malloc(sizeof(struct Node)))) return str;
newnode->ln_Name = str;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
if (index == 0) AddHead((struct List *)&s->SelList, newnode);
else Insert((struct List *)&s->SelList, newnode,
FindIndex((struct List *)&s->SelList, index-1));
s->SelTotal++;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
return str;
}
char *RemoveFirstString(Select *s)
{
struct Node *old;
char *oldstr;
if (!s->SelTotal) return NULL;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
old = RemHead((struct List *)&s->SelList);
s->SelTotal--;
if (s->SelIndex == s->SelTotal) s->SelIndex--;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
oldstr = old->ln_Name;
if (!s->NodeArray) free(old);
return oldstr;
}
char *RemoveLastString(Select *s)
{
struct Node *old;
char *oldstr;
if (!s->SelTotal) return NULL;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
old = RemTail((struct List *)&s->SelList);
s->SelTotal--;
if (s->SelIndex == s->SelTotal) s->SelIndex--;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
oldstr = old->ln_Name;
if (!s->NodeArray) free(old);
return oldstr;
}
char *RemoveString(Select *s, int index)
{
struct Node *old;
char *oldstr;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
old = FindIndex((struct List *)&s->SelList, index);
Remove(old);
s->SelTotal--;
if (s->SelIndex == s->SelTotal) s->SelIndex--;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
if (old) {
oldstr = old->ln_Name;
if (!s->NodeArray) free(old);
return oldstr;
}
return NULL;
}
*/
void RemoveAllStrings(Select *s)
{
struct Node *old;
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach
if (s->NodeArray) {
free(s->NodeArray);
s->NodeArray = NULL;
NewList((struct List *)&s->SelList);
}
else while (old = RemTail((struct List *)&s->SelList)) free(old);
if (s->SelWnd)
GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
s->SelTotal = 0;
}
void DisableSelect(Select *s, BOOL flag) {
if (s->SelWnd) {
GT_SetGadgetAttrs(s->ListView,s->SelWnd,NULL,
GA_Disabled, flag, TAG_DONE);
}
}
void CurrentIndex(Select *s, int index)
{
if (s) {
s->SelIndex = index;
if (s->SelWnd) UpdateListView(s);
}
}
int HandleSelectIDCMP(Select *s)
{
struct IntuiMessage *m;
int (*func)(Select*);
BOOL running = SEL_PRIVATE;
while( s->SelWnd && (m = GT_GetIMsg( s->SelWnd->UserPort ))) {
CopyMem(( char * )m, ( char * )&s->SelMsg, (long)sizeof( struct IntuiMessage ));
GT_ReplyIMsg( m );
switch ( s->SelMsg.Class ) {
case IDCMP_REFRESHWINDOW:
GT_BeginRefresh( s->SelWnd );
GT_EndRefresh( s->SelWnd, TRUE );
break;
case IDCMP_CLOSEWINDOW:
running = SelCloseWindow(s);
break;
case IDCMP_NEWSIZE:
running = SelNewSize(s);
break;
case IDCMP_VANILLAKEY:
running = SelVanillaKey(s);
break;
case IDCMP_RAWKEY:
running = SelRawKey(s);
break;
case IDCMP_GADGETUP:
case IDCMP_GADGETDOWN:
func = (int(*)(Select*))(( struct Gadget * )s->SelMsg.IAddress )->UserData;
if(func)
running = func(s);
break;
}
}
return( running );
}
int OpenSelect(Select *s, struct Window *parentwin, char *wintitle, char *screentitle)
{
char *bufp, *namep;
if (s->SelWnd) return 5L; /* Already opened */
if (s->SelWidth == ~0) { /* Window has never been opened before */
s->SelWidth = 220;
// ComputeFont( s->SelWidth, s->SelHeight );
s->SelWidth = ComputeX( s->SelWidth );
s->SelHeight = ComputeY( s->SelHeight );
if (parentwin) {
s->SelLeft = parentwin->LeftEdge + parentwin->Width;
s->SelTop = parentwin->TopEdge + (parentwin->Height - s->SelHeight)/2;
}
if (s->SelLeft + s->SelWidth > Scr->Width)
s->SelLeft = parentwin->LeftEdge - s->SelWidth;
}
/* Strip underscore _ for cosmethic reasons */
for (bufp = s->SelWdt, namep = wintitle; *namep; namep++)
if (*namep != '_') *bufp++ = *namep;
/* Strip trailing ':' if there's any */
if(*(bufp-1) != ':')
*bufp = ':';
else
*bufp = '\0';
s->SelCompleteBuf = bufp+1;
s->SelCompleteBuf[0] = '\0';
s->SelZoom[0] = s->SelLeft;
s->SelZoom[1] = 0;
s->SelZoom[2] = s->SelWidth;
s->SelZoom[3] = Scr->Height;
if ( ! ( s->SelWnd = OpenWindowTags( NULL,
WA_Left, s->SelLeft,
WA_Top, s->SelTop,
WA_Width, s->SelWidth,
WA_Height, s->SelHeight,
WA_IDCMP, LISTVIEWIDCMP|BUTTONIDCMP|IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_REFRESHWINDOW,
WA_Flags, WFLG_SIZEGADGET|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SIZEBBOTTOM|WFLG_SIMPLE_REFRESH|WFLG_ACTIVATE|WFLG_RMBTRAP,
WA_Title, s->SelWdt,
WA_ScreenTitle, screentitle,
WA_PubScreen, Scr,
WA_MinWidth, 160,
WA_MinHeight, 120,
WA_MaxWidth, -1,
WA_MaxHeight, -1,
WA_Zoom, s->SelZoom,
TAG_DONE )))
return( 4L );
MyCreateAllGadgets(s);
return( 0L );
}
void CloseSelect(Select *s)
{
if ( s->SelWnd ) {
s->SelLeft = s->SelWnd->LeftEdge;
s->SelTop = s->SelWnd->TopEdge;
s->SelWidth = s->SelWnd->Width;
s->SelHeight = s->SelWnd->Height;
CloseWindow( s->SelWnd );
s->SelWnd = NULL;
}
if ( s->SelGList ) {
FreeGadgets( s->SelGList );
s->SelGList = NULL;
}
}
Select *NewSelect(void)
{
/* Data för ListView gadget */
Select *s = (Select*) malloc(sizeof(Select));
if (!s) return NULL;
s->SelWnd = NULL;
s->SelGList = NULL;
s->ListView = NULL;
s->SelWidth = ~0; /* (220) Window has never been opened before */
s->SelHeight = 280;
s->SelLeft = (Scr->Width - 220) >> 1;
s->SelTop = (Scr->Height - s->SelHeight) >> 1;
s->SelIndex = 0;
s->SelTotal = 0;
s->StartSecs = 0, s->StartMicros = 0;
s->NodeArray = NULL;
NewList((struct List *)&s->SelList);
return s;
}
void DeleteSelect(Select *s)
{
CloseSelect(s);
RemoveAllStrings(s);
free(s);
}